package org.folio.rest.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.folio.cql2pgjson.exception.FieldException;
import org.folio.rest.impl.other.PartyLogSave;
import org.folio.rest.impl.other.PartyUtil;
import org.folio.rest.impl.other.blacklist.BlacklistService;
import org.folio.rest.impl.other.client.OkapiUserModulesClient;
import org.folio.rest.impl.other.client.impl.OkapiUserModulesClientImpl;
import org.folio.rest.impl.util.DBName;


import org.folio.rest.jaxrs.model.*;

import org.folio.rest.jaxrs.resource.PartyRules;
import org.folio.rest.persist.PgUtil;
import org.folio.rest.persist.PostgresClient;
import org.folio.rest.persist.cql.CQLWrapper;
import org.folio.rest.tools.utils.ValidationHelper;
import org.folio.rulez.Rules;

import javax.ws.rs.core.Response;

import java.util.*;

public class PartyRulesImpl implements PartyRules {


    @Override
    public void getPartyRules(String query, int offset, int limit, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {

        try{
            CQLWrapper cql =  PartyUtil.getCQL(query,limit,offset,DBName.NOTIFY_TABLE_PARTY_RULES);
        }catch (FieldException e){
            Errors valErr = ValidationHelper.createValidationErrorMessage("query",query,
                    "查询条件不正确!");
            asyncResultHandler.handle(Future.succeededFuture(GetPartyRulesResponse.respond400WithTextPlain(valErr)));
            return;

        }
        PgUtil.get(DBName.NOTIFY_TABLE_PARTY_RULES,
               RulesGroup.class,RuleCollection.class,
                query,offset,limit,okapiHeaders,vertxContext,GetPartyRulesResponse.class,asyncResultHandler
        );
    }

    @Override
    public void postPartyRules(String lang, Rule entity, Map<String, String> okapiHeaders,
                               Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
         //保存完毕之后,要获取所有的用户信息,为他们初始化一份行为记录 废弃 当用户达到一定规模时可能会出现莫名其妙的性能瓶颈
        //改为 每次活动结束之后, 在盘点用户参与情况时, 才初始化并记录其行为
        //这里要查找旧的规则然后作废,并且禁用旧的行为记录, 小黑屋不受影响
        //当他开启规则的时候才执行上述 同时约定一年只能有一条规则, 可以开启多条年份不同的规则
        entity.setStatus("1");
        entity.setOpenState("0");
        entity.setCreateDate(DateUtil.formatDateTime(new Date()));
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
        pg.get(DBName.NOTIFY_TABLE_PARTY_RULES,new Rule(),true,getAllReply->{
            if (getAllReply.succeeded()){
                List<Rule> oldResult = getAllReply.result().getResults();
                if (oldResult.size()>0){
                    Optional<Rule> result = oldResult.stream().filter(a -> a.getYear().equals(entity.getYear()) && a.getStatus().equals("1")).findAny();
                    if (result.isPresent()){
                        Errors valErr = ValidationHelper.createValidationErrorMessage("year",entity.getYear(),
                                "保存失败! 这个年份的黑名单规则已经存在!");
                        asyncResultHandler.handle(Future.succeededFuture(PostPartyRulesResponse.respond422WithApplicationJson(valErr)));
                        return;
                    }
                }
                pg.save(DBName.NOTIFY_TABLE_PARTY_RULES, UUID.randomUUID().toString(),entity,reply->{
                    if (reply.failed()){
                        asyncResultHandler.handle(Future.failedFuture(reply.cause()));
                        return;
                    }
                    asyncResultHandler.handle(Future.succeededFuture(PostPartyRulesResponse.respond201WithApplicationJson(entity,PostPartyRulesResponse.headersFor201())));
                    PartyLogSave.saveLog("添加年份为【" + entity.getYear() + "】的黑名单规则", 3, entity.getMetadata(), entity.getOperator(), okapiHeaders, asyncResultHandler, pg);
                });
            }
        });

    }

    @Override
    public void getPartyRulesModifyById(String id, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        PgUtil.getById(DBName.NOTIFY_TABLE_PARTY_RULES, Rule.class,id,okapiHeaders,vertxContext,GetPartyRulesModifyByIdResponse.class,asyncResultHandler);
    }

    @Override
    public void deletePartyRulesModifyById(String id, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
      //一旦出现删除的情况,名下的用户记录就全部冻结,小黑屋照常运作

//       PgUtil.deleteById(DBName.NOTIFY_TABLE_PARTY_RULES,id,okapiHeaders,vertxContext,DeletePartyRulesModifyByIdResponse.class,reply->{
//           if(reply.succeeded()){
//               asyncResultHandler.handle(Future.succeededFuture(DeletePartyRulesModifyByIdResponse.respond204()));
//           }else{
//               asyncResultHandler.handle(Future.failedFuture(reply.cause()));
//           }
//       });
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
        pg.getById(DBName.NOTIFY_TABLE_PARTY_RULES,id,Rule.class,reply->{
            if (reply.succeeded()){
                Rule old = reply.result();
                old.setStatus("0");
                old.setOpenState("0");
                pg.update(DBName.NOTIFY_TABLE_PARTY_RULES,old,id,updateReply->{
                    if (updateReply.succeeded()){
                        //根据CQL查询搜索 对应编号的行为记录
                        BlacklistService.addBlackListRule(old);
                        CQLWrapper cql=PartyUtil.CQLCreate("( conductRecordGroup == *\"ruleId\"*: *\""+id+"\"* )",-1,-1,DBName.NOTIFY_TABLE_READER_CREDIT);
                        pg.get(DBName.NOTIFY_TABLE_READER_CREDIT,ReaderCreditRecord.class,new String[]{"*"},cql,true,false,getReply->{
                            if (getReply.succeeded()){
                                List<ReaderCreditRecord> list = getReply.result().getResults();
                                if (list.size()>0){
                                    list.forEach(a->{
                                        List<ConductRecordGroup> record = a.getConductRecordGroup();
                                        record.forEach(b->{
                                            if (b.getRuleId().equals(id)){
                                                b.setStatus("0");
                                                pg.update(DBName.NOTIFY_TABLE_READER_CREDIT,a,a.getId(),update->{
                                                    if (update.succeeded()){
                                                        //
                                                    }
                                                });
                                                return;
                                            }
                                        });
                                    });

                                }
                                asyncResultHandler.handle(Future.succeededFuture(PutPartyRulesModifyByIdResponse.respond204()));
                                PartyLogSave.saveLog("删除年份为【" + old.getYear() + "】的黑名单规则", 4, old.getMetadata(), old.getOperator(), okapiHeaders, asyncResultHandler, pg);
                            }
                        });
                    }
                });

            }
        });
    }

    @Override
    public void putPartyRulesModifyById(String id, String lang, Rule entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
       //如果一旦出现修改的情况,就要先把旧的冻结,保存新的,并且操作黑名单记录表
//        PgUtil.put(DBName.NOTIFY_TABLE_PARTY_RULES,entity,id,okapiHeaders,vertxContext,PutPartyRulesModifyByIdResponse.class,reply->{
//            if (reply.succeeded()){
//                asyncResultHandler.handle(Future.succeededFuture(PutPartyRulesModifyByIdResponse.respond204()));
//            }else{
//                asyncResultHandler.handle(Future.failedFuture(reply.cause()));
//            }
//        });
        //一旦出现修改 , 原有的用户行为记录就要作废 ,并赋予新的行为记录 ,黑名单不受影响
        //需要区分,暂时处于小黑屋的用户行为记录吗, 我认为不需要,因为在小黑屋的始终会被限制记录行为,所以全部重置即可
       PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
       pg.getById(DBName.NOTIFY_TABLE_PARTY_RULES,id,RulesGroup.class,reply->{
           if (reply.succeeded()){
               pg.update(DBName.NOTIFY_TABLE_PARTY_RULES,entity,id,updateReply->{
                   if (updateReply.succeeded()){
                       //根据CQL查询搜索 对应编号的行为记录
                       updateReaderCreate(id, asyncResultHandler, pg );
                   }
                   PartyLogSave.saveLog("修改年份为【" + entity.getYear() + "】的黑名单规则", 4, entity.getMetadata(), entity.getOperator(), okapiHeaders, asyncResultHandler, pg);
               });
           }
       });
//       PgUtil.getById(DBName.NOTIFY_TABLE_PARTY_RULES
//               ,RulesGroup.class,id,okapiHeaders,vertxContext
//               ,GetPartyRulesModifyByIdResponse.class,reply->{
//           if (reply.succeeded()){
//               Rule rule = (Rule) reply.result().getEntity();
//               entity.setId(rule.getId());
//               pg.update(DBName.NOTIFY_TABLE_PARTY_RULES,);
//           }
//       });

    }

    private void updateReaderCreate(String id, Handler<AsyncResult<Response>> asyncResultHandler, PostgresClient pg ) {
        CQLWrapper cql=PartyUtil.CQLCreate("( conductRecordGroup == *\"ruleId\"*: *\""+ id +"\"* )",-1,-1,DBName.NOTIFY_TABLE_READER_CREDIT);
        pg.get(DBName.NOTIFY_TABLE_READER_CREDIT,ReaderCreditRecord.class,new String[]{"*"},cql,true,false, getReply->{
             if (getReply.succeeded()){
                 List<ReaderCreditRecord> list = getReply.result().getResults();
                 if (list.size()>0){
                     list.forEach(a->{
                         List<ConductRecordGroup> record = a.getConductRecordGroup();
                         record.forEach(b->{
                             if (b.getRuleId().equals(id)){
                                 b.setAbsence(0);
                                 b.setBeLate(0);
                                 b.setLeave(0);
                                 b.setLeaveEarly(0);
                                 b.setStatus("1");
                                 pg.update(DBName.NOTIFY_TABLE_READER_CREDIT,a,a.getId(), update->{
                                     if (update.succeeded()){
                                         //
                                     }
                                 });
                                 return;
                             }
                         });
                     });

                 }
                 asyncResultHandler.handle(Future.succeededFuture(PutPartyRulesModifyByIdResponse.respond204()));

             }
        });
    }

    @Override
    public void putPartyRulesSwitchById(String id, String lang, Rule entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        if (entity.getOpenState() == null)
        {
            Errors valErr = ValidationHelper.createValidationErrorMessage("openState",""+entity.getOpenState(),
                    "保存失败! 值不能为空");
            asyncResultHandler.handle(Future.succeededFuture(PostPartyRulesResponse.respond422WithApplicationJson(valErr)));
            return;
        }
        if ("0".equals(entity.getOpenState()) && "1".equals(entity.getOpenState()))
        {
            Errors valErr = ValidationHelper.createValidationErrorMessage("openState",""+entity.getOpenState(),
                    "保存失败! 值的范围不正确");
            asyncResultHandler.handle(Future.succeededFuture(PostPartyRulesResponse.respond422WithApplicationJson(valErr)));
            return;
        }
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
        pg.getById(DBName.NOTIFY_TABLE_PARTY_RULES,id,RulesGroup.class,reply-> {
            if (reply.succeeded()) {
                RulesGroup rule = reply.result();
                rule.setOpenState(entity.getOpenState());
                pg.update(DBName.NOTIFY_TABLE_PARTY_RULES,rule,id,updateReply-> {
                    if (updateReply.succeeded()) {
                        BlacklistService.addBlackListRule(entity);
                        updateReaderCreate(id, asyncResultHandler, pg);
                    }else{
                        asyncResultHandler.handle(Future.succeededFuture(PutPartyRulesSwitchByIdResponse.respond500WithTextPlain(updateReply.cause())));
                    }
                });
            }
        } );
    }
}
